package buss

import (
	_ "database/sql"
	log "github.com/cihub/seelog"
	_ "github.com/go-sql-driver/mysql"
	"github.com/jinzhu/gorm"
	"github.com/muesli/cache2go"
	"time"
	"encoding/json"
	"strconv"
)

type Dao struct {
}

var cache *cache2go.CacheTable

const (
	siteConfig = "siteConfig"
	allCategories = "allCategories"
	recommendCategories = "recommendcategories"
	recommendIcons = "recommendIcons"
	recentIcons = "recentIcons"
	hotIcons = "hotIcons"
	item = "item"
	categoriy= "categoriy"
)

func (dao Dao) Init() {
	cache = cache2go.Cache("myCache")
}

type AppName struct {
	Id   int `gorm:"primary_key"`
	Name string `gorm:"column:name"`
}
type AppBase struct {
	AppName
	CreateDate string `gorm:"column:createDate"`
	ErCode     string `gorm:"column:ercode"`
	Ico        string `gorm:"column:ico"`
	Tags       string `gorm:"column:tags"`
	Introduce  string `gorm:"column:introduce"`
}
type App struct {
	AppBase
	Type     string `gorm:"column:type"`
	TypeName string `gorm:"column:typename"`
}

type AppExtInfo struct {
	AppBase
	Url         string `gorm:"column:url"`
	View        int    `gorm:"column:view"`
	Status      int    `gorm:'column:status"`
	Recommend   int    `gorm:"column:recommend"`
	Star        string `gorm:"column:star"`
	Screenshots string `gorm:"column:screenshots"`
}
type AppType struct {
	Id   int    `gorm:"primary_key"`
	Name string `gorm:"column:name"`
	//Sum string `gorm:"column:sum"`
}

type TypeApps struct {
	Id     int    `gorm:"primary_key"`
	AppId  int   `gorm:"column:appid"`
	TypeId int  `gorm:"column:typeid"`
}

func (AppType) TableName() string {
	return "tbl_app_type"
}

type ICON struct {
	Id   string `gorm:"primary_key"`
	Ico  string `gorm:"column:ico"`
	Name string `gorm:"column:name"`
}

type RecommendIcon struct {
	ICON
	Tags string `gorm:"column:tags"`
}

type SiteConfig struct {
	Id       string `gorm:"primary_key"`
	ICO      string `gorm:"column:logo"`
	SiteName string `gorm:"column:sitename"`
}

func (Dao) QueryForRecommendTypeList() []AppType {
	var appTypes []AppType
	config, error := cache.Value(recommendCategories)
	if error != nil {
		db := initDb()
		defer db.Close()

		db.Table("tbl_app_type").Select("id,name").Where("isshow=?", 1).Order("id desc ").Limit(8).Scan(&appTypes)
		cache.Add(recommendCategories, 10 * time.Minute, appTypes)
	} else {
		appTypes = config.Data().([]AppType)
	}
	return appTypes
}

func (Dao) QueryForAllTypeList() []AppType {
	var appTypes []AppType
	config, error := cache.Value(allCategories)
	if error != nil {
		db := initDb()
		defer db.Close()
		//db.Table("tbl_app_type a").Joins("left join tbl_app_type  b  on a.id = b.typeid").Select("a.id,b.name").Order("a.id desc ").Scan(&appTypes)
		db.Table("tbl_app_type").Select("id,name").Order("id desc ").Scan(&appTypes)
		cache.Add(allCategories, 10 * time.Minute, appTypes)
	} else {
		appTypes = config.Data().([]AppType)
	}
	return appTypes
}

func (dao Dao) QueryForSiteConfig() *SiteConfig {
	var site SiteConfig
	config, error := cache.Value(siteConfig)
	if error != nil {
		db := initDb()
		defer db.Close()
		db.Table("tbl_config").Select("id,logo,sitename").First(&site)
		cache.Add(siteConfig, 5 * time.Minute, site)
	} else {
		site = config.Data().(SiteConfig)
	}
	return &site
}

func (Dao) QueryForHotIconsList() []ICON {
	var icons []ICON
	result, error := cache.Value(hotIcons)
	if error != nil {
		dbmap := initDb()
		db := initDb()
		defer db.Close()
		dbmap.Table("tbl_app").Select("id,ico,name").Where("status =?", 0).Order("view desc ,id desc").Limit(12).Scan(&icons)
		cache.Add(hotIcons, 5 * time.Minute, icons)
	} else {
		icons = result.Data().([]ICON)
	}
	return icons
}

func (Dao) QueryForRecommendIconsList() []ICON {
	var icons []ICON
	result, error := cache.Value(recommendIcons)
	if error != nil {
		dbmap := initDb()
		defer dbmap.Close()
		dbmap.Table("tbl_app").Select("id,ico,name").Where("status =?", 0).Where("recommend =?", 1).Order("id desc").Limit(12).Scan(&icons)
		cache.Add(recommendIcons, 5 * time.Minute, icons)
		return icons
	} else {
		icons = result.Data().([]ICON)
		return icons
	}
}
func (Dao) QueryForRecentIconsList() []ICON {
	var icons []ICON
	result, error := cache.Value(recentIcons)
	if error != nil {
		dbmap := initDb()
		defer dbmap.Close()
		dbmap.Table("tbl_app").Select("id,ico,name").Where("status =?", 0).Order("id desc").Limit(12).Scan(&icons)
		cache.Add(recentIcons, 5 * time.Minute, icons)
	} else {
		icons = (result.Data().([]ICON))
	}
	return icons
}

func (Dao) QueryForRecommendIconsListByType(typeId int, id  int) []ICON {
	var icons []ICON
	result, error := cache.Value(recentIcons)
	if error != nil {
		dbmap := initDb()
		defer dbmap.Close()
		dbmap.Table("  tbl_type b   ").Select("a.id, a.ico,a.name").Where("a.status = ?", 0).Where("b.status = ?", 0).Where("b.typeId=?", typeId).Where("b.appId > ?", id).Joins("left join tbl_app  a on  a.id = b.appid").Limit(12).Offset(0).Find(&icons)
		cache.Add(recentIcons, 5 * time.Minute, icons)
	} else {
		icons = (result.Data().([]ICON))
	}
	return icons
}

func (Dao) QueryForTypeById(id int) *AppType  {
	var appType AppType
	 key :=categoriy +"-"+strconv.Itoa(id)
	result, error := cache.Value(key)
	if error != nil {
		dbmap := initDb()
		defer dbmap.Close()
		dbmap.FirstOrCreate(&appType, id)
		cache.Add(key, 5 * time.Minute, appType)
	}else {
		appType = (result.Data().(AppType))
	}
	return &appType
}

func (Dao) QueryForTypeByName(name string) *AppType  {
	var appType AppType
	key :=categoriy +"-"+name
	result, error := cache.Value(key)
	if error != nil {
		dbmap := initDb()
		defer dbmap.Close()
		dbmap.FirstOrCreate(&appType, AppType{Name: name})
		cache.Add(key, 5 * time.Minute, appType)
	}else {
                appType = (result.Data().(AppType))
        }
       return &appType
}
func (Dao) QueryAppByName(name string) bool {
	dbmap := initDb()
	defer dbmap.Close()
	var count int
	dbmap.Table("tbl_app ").Where("name=?", name).Count(&count)
	if count == 1 {
		return true
	} else {
		return false
	}
}
func (Dao) SaveApp(app AppExtInfo) bool {
	dbmap := initDb()
	defer dbmap.Close()
	dbmap.Table("tbl_app").Attrs(app).FirstOrCreate(&app, map[string]interface{}{"Name": app.Name})
	tags := []byte(app.Tags)
	var tag map[string]string
	json.Unmarshal(tags, &tag)
	appId := app.Id
	for k,_:= range tag {
		typeId, _ := strconv.Atoi(k)
		var typeApps TypeApps
		typeApps.TypeId = typeId
		typeApps.AppId = appId

		dbmap.Table("tbl_type").Attrs(typeApps).FirstOrCreate(&typeApps, map[string]interface{}{"typeId": typeId, "appid":appId})
		log.Debugf("save typeApps:  %v ", typeApps)
	}
	return true
}

func (Dao) QueryForIconsListByType(typeId int, page, size int) []ICON {
	var icons []ICON
	key  :=categoriy+"-" +strconv.Itoa(typeId)+"-"+strconv.Itoa(page)
	result, error := cache.Value(key)
	if error != nil {

		dbmap := initDb()
		defer dbmap.Close()
		log.Debugf("typeId:%s  curpage:%d    size:%d", typeId, page, size)

		dbmap.Table("  tbl_type b   ").Select("a.id, a.ico,a.name").Where("a.status = ?", 0).Where("b.status = ?", 0).Where("b.typeId=?", typeId).Joins("left join tbl_app  a on  a.id = b.appid").Limit(size).Offset((page - 1) * size).Find(&icons)
		cache.Add(key, 5 * time.Minute, icons)
	}else {
		icons = (result.Data().([]ICON))
	}
		return icons
}

func (Dao) QueryForApp(id int) *AppExtInfo {
	var app AppExtInfo
	result, error := cache.Value(item+strconv.Itoa(id))
	if error != nil {
		dbmap := initDb()
		defer dbmap.Close()
		dbmap.Table("tbl_app ").Find(&app, id)
		cache.Add(item+strconv.Itoa(id), 5 * time.Minute, app)
	}else {
		app = (result.Data().(AppExtInfo))
	}
	return &app
}

func (dao Dao) QueryForCountByType(id int, pageSize int) (int, string) {
	dbmap := initDb()
	defer dbmap.Close()
	var total int
	dbmap.Table("tbl_type").Where("typeid=?", id).Count(&total)
	log.Debugf("total:  %d\n", total)
	var totalPage int
	if total % pageSize == 0 {
		totalPage = total / pageSize
	} else {
		totalPage = total / pageSize + 1
	}
	appType:=dao.QueryForTypeById(id)
	return totalPage, appType.Name
}

func (Dao) UpdateAppView(id int) bool {
	dbmap := initDb()
	defer dbmap.Close()
	var app AppExtInfo
	dbmap.Table("tbl_app").Select("view").First(&app, id)
	dbmap.Table("tbl_app").Model(&app).Where("id=?", id).Update("view", app.View + 1)
	return true
}

func initDb() *gorm.DB {
	db, err := gorm.Open("mysql", "root:test@tcp(localhost:3306)/miniapp")
	if err != nil {
		panic(err)
	}
	db.LogMode(true)    //调试sql模式
	return db
}
